Repository navigation
InnerLayer.SLAYER - FEATURE! - Build P_perp from the perpendicular particle diffusivity by default and add an ion heat diffusivity profile - #501
Conversation
… kinetic HDF5 Add an optional chi_i (ion perpendicular heat diffusivity) dataset to the kinetic-profile reader and writer, alongside chi_e and chi_phi. Ship chi_i in the DIII-D-like example kinetic file, built like its chi_e: AOT CHI_I of DIII-D 147131 at 2300 ms, mapped rho_N -> psi_N with EFIT01 RHOVN, the spurious zero at psi_N = 1 dropped, Gaussian-smoothed with sigma = 12 of 201 rho_N points (the width that best reproduces the example chi_e from AOT CHI_E). Range 0.46-2.1 m^2/s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…i_perp to chi_perp_e New [SLAYER] P_perp_model selects how the perpendicular Prandtl number is built: - chi_perp_e (default, unchanged numbers): tau_R*chi_perp_e/r_s^2 - chi_perp_i: tau_R*chi_perp_i/r_s^2 (kinetic-file chi_i, scalar fallback) - P_phi: P_perp = P_tor (Fitzpatrick, Phys. Plasmas 30, 092512 (2023), Eq. 143) - D_perp: tau_perp = r_s^2/D_perp (Fitzpatrick, Phys. Plasmas 29, 032507 (2022)) - c_beta: C^2 = P_perp with C = c_beta (Park et al., Phys. Plasmas 29, 122505 (2022)) Breaking: the [SLAYER] chi_perp key is renamed chi_perp_e. chi_perp_e still sets the critical-Delta offset in every mode. Regression harness diiid_slayer_n1 develop vs local: 17 unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…= tau_R/tau_E) A single [SLAYER] tau_E [s] for the whole plasma sets P_perp = P_tor = tau_R/tau_E at every surface (Fitzpatrick, Phys. Plasmas 30, 092512 (2023), Eq. 131). validate() requires a positive tau_E when this model is selected. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…. 16
P_perp_model = D_perp now builds D_perp per surface from Eq. 16 of Fitzpatrick,
Phys. Plasmas 29, 032507 (2022), with eta_perp = eta_par:
D_perp = c_beta^2 eta/mu0 + (2/3)(1 - c_beta^2)[eta_e tau_e/(1+eta_e) chi_perp_e
+ eta_i tau_i/(1+eta_i) chi_perp_i]
using the n, T_e, T_i log-gradients at the surface (Eqs. 4-6, written flat-density
safe). The scalar D_perp input is removed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e DIII-D-like SLAYER example Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Effect of each
|
P_perp_model |
P_⊥ (2/1, 3/1, 4/1) | P_φ (2/1, 3/1, 4/1) | γ [Hz] (2/1, 3/1, 4/1) | Δγ vs default (2/1, 3/1, 4/1) | ω [Hz] 2/1 |
|---|---|---|---|---|---|
chi_perp_e |
50.3, 44, 35.7 | 34.7, 24.7, 19 | 192, -251, -1012 | — | -10527 |
chi_perp_i |
29.9, 26.4, 12.5 | 34.7, 24.7, 19 | 213, -274, -1217 | +11 %, -9 %, -20 % | -10523 |
P_phi |
34.7, 24.7, 19 | 34.7, 24.7, 19 | 206, -277, -1123 | +8 %, -10 %, -11 % | -10525 |
D_perp |
16.4, 17.5, 10.9 | 34.7, 24.7, 19 | 242, -296, -1249 | +26 %, -18 %, -23 % | -10516 |
c_beta |
0.0133, 0.0088, 0.00645 | 34.7, 24.7, 19 | 313, -588, -1669 | +63 %, -134 %, -65 % | -10133 |
tau_E |
34.5, 30.8, 27.6 | 34.5, 30.8, 27.6 | 206, -264, -1034 | +8 %, -5 %, -2 % | -10525 |
The Δγ column is (γ − γ_default)/|γ_default|, so + means more unstable. For scale, the run-to-run AMR noise on γ is about 0.01 %.
Takeaways
- Only
c_betachanges the answer qualitatively. Its P_⊥ = c_β² ≈ 0.01, three to four orders of magnitude below every other model. The 2/1 drive rises about 60 %, the stable 3/1 and 4/1 roots damp 65–135 % harder, and ω on the 2/1 shifts about 4 %. Every other model shifts ω by less than 0.1 %. - The χ-based models move γ by roughly 10–25 %.
chi_perp_iuses the example's χ⊥,i, which is about 0.4–0.6 of χ⊥,e at these surfaces. That halves P_⊥ and moves γ by about 10 % at the 2/1 and 3/1 and 20 % at the 4/1.D_perpgives the smallest P_⊥ of the transport-based models, so it moves γ the furthest, by 18–26 %.- Across these models, a lower P_⊥ makes the 2/1 more unstable and the 3/1 and 4/1 more stable.
P_phiandtau_Eland close together. With τ_E = 0.1 s, τ_R/τ_E happens to be close to the χ_φ-based P_φ on the 2/1.tau_Ealso overrides P_φ, so its 3/1 and 4/1 sit nearer the default. γ scales with the chosen τ_E, so these numbers only illustrate the model.chi_perp_e(the default) reproduces develop exactly; see the regression report in the PR description.
The unit tests (Pkg.test() at 27d0744 on feynman) pass.
🤖 Generated with Claude Code
Example kinetic-file χ profiles vs the DIII-D 147131 AOT sourceEach panel compares
At the SLAYER surfaces (new
Notes
🤖 Generated with Claude Code |
… and describe c_beta as the no-transport limit of D_perp The SLAYER file headers and the c_beta P_perp_model cited "Park et al., Phys. Plasmas 29, 122505 (2022)", which does not exist. The paper is J.-K. Park, Phys. Plasmas 29, 072506 (2022), doi:10.1063/5.0093079, as docs/src/citations.md already lists. Its Eq. 10 defines C² = c_β² + (1 − c_β²)K; C = c_β drops the thermal-conduction K, which makes P_perp = c_β² the χ⊥ → 0 limit of the D_perp model. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…o feature/slayer-pperp-models
|
@logan-nc @d-burg This adds a variety of options for perpendicular diffusion inputs. It doesn't change the default yet, so selecting the chi_perp_e is the same as what currently exists. You can see in the comparison that the only really different one is the c_beta which is good news (and encouragement to have this increased fidelity vs the Fortran slayer implementation). I think that we should move to full D_perp as default since there is not a literature justification for chi_perp_e ~ D_perp and if people already need chi_phi and chi_perp_e inputs than its not too crazy to also have them input chi_perp_i. It's encouraging that the tau_E choice is right order of magnitude (using tau_E = chi_phi and P_perp = P_phi) so that is also a helpful, user friendly, and control friendly option. After this gets merged, then either @d-burg or I should make a PR changing the default to D_perp and removing the chi_perp_e and chi_perp_i options. Let me know if you have any questions on this. Thanks! |
|
At a high level, this looks good. I agree that if someone has chi_phi and chi_perp_e, they likely have chi_perp_i on hand. If they don't have things, or are lazy then letting them assert a "reasonable" tau_E for their device is a great way to get results quick. |
d-burg
left a comment
There was a problem hiding this comment.
Thanks -- the switch is cleanly done, the default path is the same arithmetic as before, and the rename is complete. I checked the new models against the papers: D_perp matches Fitzpatrick (2022) Eqs. 4–6 and 16, c_beta matches Park (2022) and is the exact χ⊥ → 0 limit of the coded D_perp, and P_phi matches Fitzpatrick (2023) Eq. 143. tau_E does not yet match Eq. 131 (inline at line 400). I also compared the old and new example file: only chi_i and the provenance text were added, and every pre-existing dataset is byte-identical.
A mix of top level feedback from myself and claude:
Blocking
- Docs CI. Two docstring lines parse as Markdown links (suggestion inline at
LayerParameters.jl:220). - Rebase onto develop. This now conflicts in 7 files since #298 landed. Note for the binary file: #298 raised
chi_einTkMkr_D3Dlike_Hmode_kinetic.h5, and this branch's copy predates that, sochi_ineeds to be added to develop's file rather than taking this branch's version, otherwise thechi_echange is undone. Thechi_i/chi_eratios in your table will change accordingly.
On making D_perp the default and removing chi_perp_e / chi_perp_i
I agree D_perp is the better-founded model, but I'd settle a few things before switching:
D_perpis Fitzpatrick's derived perpendicular particle diffusivity: c_β²η⊥/μ₀ plus (2/3)(1 − c_β²)(n T_e′χ⊥,e + n T_i′χ⊥,i)/p′, built from the electron and ion energy diffusivities. By comparisonchi_perp_eis an electron-only proxy, so I'd describe it in the docstring and release note as the backward-compatible choice rather than "the" P⊥. One caveat for the default: where the temperature profiles are flat, Eq. 16 reduces to thec_betafloor, which your table shows moves γ by 60–130 %, so flat-temperature regions of a real profile would change answers a lot.tau_Eneeds fixing before it is advertised as the quick option: Eq. 131's τ_E is the local r²/χ_E, not the whole-plasma confinement time, so as documented this mode is off by r̂_s²/κ_e (details inline).- χ⊥,e stays a required input in every mode because it sets the critical-Δ width, so it can't go away even if the model option does. This PR is already a breaking rename of a key every SLAYER deck sets; I'd rather agree the end state now so users migrate once.
- Please add one harness case with a non-default
P_perp_model(your table already has the reference numbers), so a later default change has a baseline.
Data question. The example file's provenance attribute now names DIII-D 147131 at 2300 ms as the source of chi_i; the previous text named no shot. Has releasing this AOT-derived profile in a public repository been cleared under the DIII-D data policy? Since the provenance is being rewritten anyway, it should also use the dataset names chi_e and chi_phi, not "chi_perp" and "chi_tor".
Small, outside the diff
docs/src/kinetic_forces.mddocuments the kinetic HDF5 schema withoutchi_iand callschi_e"the" perpendicular heat diffusivity; therun_slayerdocstring likewise mentions onlychi_e/chi_phi.- An old deck with
chi_perp = ...is rejected by the generic unknown-key error, which is the important part, but a one-line hint whenchi_perpis among the unknown keys ("renamed to chi_perp_e") would save users a search through several dozen names. - Fitzpatrick (2022) and (2023) are cited for three of the six models but aren't in
docs/resources; adding them would let later reviewers check the equations.
| - `chi_perp_i` -- ion perpendicular heat diffusivity [m²/s] (used by `P_perp_model=:chi_perp_i`) | ||
| - `dlnn`, `dlnTe`, `dlnTi` -- radial log-gradients of n, T_e, T_i in any common radial variable | ||
| (only their ratios enter; required by `P_perp_model=:D_perp`) | ||
| - `tau_E` -- whole-plasma energy confinement time [s] (required by `P_perp_model=:tau_E`) |
There was a problem hiding this comment.
These two lines are what fails the Documentation job: [m²/s] (used by ...) and [s] (required by ...) parse as Markdown links (the parser skips the space between ] and (), and this docstring is spliced into inner_layer.md. A comma after the unit bracket, as the build_slayer_inputs docstring already does, removes both. The suggestion also adds :D_perp to the models that use chi_perp_i.
| - `chi_perp_i` -- ion perpendicular heat diffusivity [m²/s] (used by `P_perp_model=:chi_perp_i`) | |
| - `dlnn`, `dlnTe`, `dlnTi` -- radial log-gradients of n, T_e, T_i in any common radial variable | |
| (only their ratios enter; required by `P_perp_model=:D_perp`) | |
| - `tau_E` -- whole-plasma energy confinement time [s] (required by `P_perp_model=:tau_E`) | |
| - `chi_perp_i` -- ion perpendicular heat diffusivity [m²/s], used by `P_perp_model=:chi_perp_i` and `:D_perp` | |
| - `dlnn`, `dlnTe`, `dlnTi` -- radial log-gradients of n, T_e, T_i in any common radial variable | |
| (only their ratios enter; required by `P_perp_model=:D_perp`) | |
| - `tau_E` -- whole-plasma energy confinement time [s], required by `P_perp_model=:tau_E` |
| # D_⊥ from Fitzpatrick, Phys. Plasmas 29, 032507 (2022), Eqs. 4-6 and 16 (η_⊥ = η_∥), with | ||
| # η_s/(1+η_s) = dlnT_s/(dlnn+dlnT_s) and τ = (T_e/T_i)(1+η_e)/(1+η_i) written flat-density safe. | ||
| frac_e = dlnTe / (dlnn + dlnTe) | ||
| frac_i = dlnTi / (dlnn + dlnTi) | ||
| tau_F = (t_e / t_i) * (dlnn + dlnTe) / (dlnn + dlnTi) | ||
| D_perp = c_beta^2 * eta / MU_0 + | ||
| (2 / 3) * (1 - c_beta^2) * (frac_e * tau_F / (1 + tau_F) * chi_perp_e + frac_i / (1 + tau_F) * chi_perp_i) |
There was a problem hiding this comment.
I checked this against Fitzpatrick (2022) Eqs. 4–6 and 16: the expression and the docstring formula match the paper. Two small things.
The intermediate ratios have a singularity the formula itself does not: with a vanishing ion (or electron) pressure gradient, frac_i and tau_F both go infinite and the product gives Inf·0 = NaN, so this throws although Eq. 16 is finite there. Writing the weights over one common denominator is the same arithmetic (η_e τ_e/(1+η_e) = T_e·dlnTe/dp and likewise for ions), leaves only p′ = 0 singular, and makes the physical content visible: the bracket is (n T_e′ χ⊥,e + n T_i′ χ⊥,i)/p′.
| # D_⊥ from Fitzpatrick, Phys. Plasmas 29, 032507 (2022), Eqs. 4-6 and 16 (η_⊥ = η_∥), with | |
| # η_s/(1+η_s) = dlnT_s/(dlnn+dlnT_s) and τ = (T_e/T_i)(1+η_e)/(1+η_i) written flat-density safe. | |
| frac_e = dlnTe / (dlnn + dlnTe) | |
| frac_i = dlnTi / (dlnn + dlnTi) | |
| tau_F = (t_e / t_i) * (dlnn + dlnTe) / (dlnn + dlnTi) | |
| D_perp = c_beta^2 * eta / MU_0 + | |
| (2 / 3) * (1 - c_beta^2) * (frac_e * tau_F / (1 + tau_F) * chi_perp_e + frac_i / (1 + tau_F) * chi_perp_i) | |
| # D_⊥ from Fitzpatrick, Phys. Plasmas 29, 032507 (2022), Eqs. 4-6 and 16 (η_⊥ = η_∥); the weights η_s τ_s/(1+η_s) equal n T_s'/p'. | |
| dp = t_e * (dlnn + dlnTe) + t_i * (dlnn + dlnTi) | |
| D_perp = c_beta^2 * eta / MU_0 + | |
| (2 / 3) * (1 - c_beta^2) * (t_e * dlnTe * chi_perp_e + t_i * dlnTi * chi_perp_i) / dp |
It would also help to say in the docstring what Eq. 16 implies at the edges, since users may be surprised: where T_e and T_i are flat, the χ terms vanish and P⊥ falls to the c_beta value (≈ 0.01 here), and where the species pressure gradients have opposite signs (hollow density) the weights can exceed 1. A test at a flat-temperature point would pin the first.
| chi_perp::Real, chi_tor::Real, | ||
| chi_perp_e::Real, chi_tor::Real, | ||
| m::Integer, n::Integer, | ||
| chi_perp_i::Real=1.0, tau_E::Real=NaN, |
There was a problem hiding this comment.
tau_E and the log-gradients default to NaN so that a model which needs them fails loudly, but chi_perp_i defaults to 1.0 m²/s, so :chi_perp_i or :D_perp called without it returns a plausible-looking number. I'd default it to NaN here and in build_slayer_inputs, and move the isfinite(...) && ... > 0 check out of the :D_perp branch to just after the if block so it applies to P_perp for every model: today a zero, negative or NaN χ⊥,i (a partly-zero profile, or spline undershoot) gives P⊥ ≤ 0 in :chi_perp_i mode with no error.
| + `:D_perp` -- τ_R/τ_⊥ with τ_⊥ = r_s²/D_⊥ and D_⊥ from Eq. 16 of Fitzpatrick, Phys. Plasmas 29, | ||
| 032507 (2022), with η_⊥ = η_∥: | ||
| D_⊥ = c_β² η/μ₀ + (2/3)(1 − c_β²)[η_e τ_e/(1+η_e) χ⊥,e + η_i τ_i/(1+η_i) χ⊥,i] | ||
| + `:c_beta` -- P_perp = C² with C = c_β (J.-K. Park, Phys. Plasmas 29, 072506 (2022), Eq. 10, with the |
There was a problem hiding this comment.
Small citation fix: in Park (2022) the C² term is in Eq. (9) and is defined in the text just below Eq. (10); Eq. (10) itself carries P, which is our P_tor. I'd cite "Eq. 9, with C² = c_β² + (1 − c_β²)K and K = 0" here and at line 423. On line 230, please also define τ_e = τ/(1+τ), τ_i = 1/(1+τ), η_s = dlnT_s/dlnn, and note that this τ is (T_e/T_i)(1+η_e)/(1+η_i), the opposite orientation to the tau = T_i/T_e field of SLAYERParameters.
| chi_perp_e = loaded.chi_perp_e === nothing ? control.chi_perp_e : loaded.chi_perp_e | ||
| chi_tor = loaded.chi_tor === nothing ? control.chi_tor : loaded.chi_tor | ||
| (loaded.chi_perp === nothing || loaded.chi_tor === nothing) && @warn( | ||
| (loaded.chi_perp_e === nothing || loaded.chi_tor === nothing) && @warn( |
There was a problem hiding this comment.
In tau_E mode P_tor is replaced by τ_R/τ_E, so the file's chi_phi and the scalar chi_tor are ignored; that is only stated in the slayer_parameters docstring. Please say it in the SLAYERControl docstring and the TOML annotation too (suggestion on the example deck), and log one @info when the mode is active. This warning should also depend on the model: as written it reports a chi_tor fallback in tau_E mode, and a chi_perp_e fallback in c_beta, P_phi and tau_E mode with dc_type = "none", where those values do not enter the result.
| chi_perp_e = 1.0 # fallback only; the kinetic file supplies χ⊥,e(ψ) | ||
| chi_perp_i = 1.0 # fallback only; the kinetic file supplies χ⊥,i(ψ) | ||
| chi_tor = 1.0 # fallback only; the kinetic file supplies χ_φ(ψ) | ||
| P_perp_model = "chi_perp_e" # Perpendicular Prandtl number model: "chi_perp_e", "chi_perp_i", "P_phi", "D_perp", "c_beta", or "tau_E" (needs tau_E [s]) |
There was a problem hiding this comment.
| P_perp_model = "chi_perp_e" # Perpendicular Prandtl number model: "chi_perp_e", "chi_perp_i", "P_phi", "D_perp", "c_beta", or "tau_E" (needs tau_E [s]) | |
| P_perp_model = "chi_perp_e" # Perpendicular Prandtl number model: "chi_perp_e", "chi_perp_i", "P_phi", "D_perp", "c_beta", or "tau_E" (needs tau_E [s]; also replaces the χ_φ-based P_tor) |
| # η_e = 2, η_i = 3, T_e = T_i ⇒ τ = 3/4, τ_e = 3/7, τ_i = 4/7 | ||
| d1 = slayer_parameters(; base..., P_perp_model=:D_perp, grads..., chi_perp_i=2.0) | ||
| D_hand = d1.c_beta^2 * d1.eta / MU_0 + (2 / 3) * (1 - d1.c_beta^2) * ((2 / 3) * (3 / 7) * 1.0 + (3 / 4) * (4 / 7) * 2.0) | ||
| @test d1.P_perp ≈ d1.tau_r * D_hand / d1.rs^2 rtol = 1e-12 |
There was a problem hiding this comment.
With T_e = T_i this check passes whichever way round the temperature ratio is written, and the struct's own tau is T_i/T_e, so I'd add a T_e ≠ T_i point (hand numbers: τ = 3/2, τ_e = 3/5, τ_i = 2/5; not run). One build_slayer_inputs test with P_perp_model=:D_perp would also cover the gradient forwarding from the profile splines, which is otherwise untested. I haven't run this test myself so this is just a suggestion, you should confirm on your end whether it checks out.
| @test d1.P_perp ≈ d1.tau_r * D_hand / d1.rs^2 rtol = 1e-12 | |
| @test d1.P_perp ≈ d1.tau_r * D_hand / d1.rs^2 rtol = 1e-12 | |
| # T_e = 2T_i ⇒ τ = 3/2, τ_e = 3/5, τ_i = 2/5: fixes the orientation of the temperature ratio | |
| d2 = slayer_parameters(; base..., t_e=2000.0, P_perp_model=:D_perp, grads..., chi_perp_i=2.0) | |
| D_hand2 = d2.c_beta^2 * d2.eta / MU_0 + (2 / 3) * (1 - d2.c_beta^2) * ((2 / 3) * (3 / 5) * 1.0 + (3 / 4) * (2 / 5) * 2.0) | |
| @test d2.P_perp ≈ d2.tau_r * D_hand2 / d2.rs^2 rtol = 1e-12 |
| ctrl.P_perp_model in _VALID_P_PERP_MODELS || | ||
| throw(ArgumentError("SLAYERControl: P_perp_model=$(ctrl.P_perp_model) " * | ||
| "not in $(_VALID_P_PERP_MODELS)")) | ||
| ctrl.P_perp_model !== :tau_E || (ctrl.tau_E !== nothing && ctrl.tau_E > 0) || |
There was a problem hiding this comment.
Missing, non-positive and NaN tau_E are caught here, but inf gets through and only fails later inside slayer_parameters, after the equilibrium and stability stages. Adding isfinite makes the two checks agree.
| ctrl.P_perp_model !== :tau_E || (ctrl.tau_E !== nothing && ctrl.tau_E > 0) || | |
| ctrl.P_perp_model !== :tau_E || (ctrl.tau_E !== nothing && isfinite(ctrl.tau_E) && ctrl.tau_E > 0) || |
| isfinite(tau_E) && tau_E > 0 || | ||
| throw(ArgumentError("slayer_parameters: P_perp_model=:tau_E needs a positive tau_E, got $tau_E")) | ||
| # P_⊥ = P_φ = τ_R/τ_E (Fitzpatrick, Phys. Plasmas 30, 092512 (2023), Eq. 131) | ||
| P_tor = tau_r / tau_E |
There was a problem hiding this comment.
I checked this against Fitzpatrick (2023), Phys. Plasmas 30, 092512. Eq. 131 is P⊥ = P_φ = τ_R/τ_E, but the τ_E there is the local energy confinement time τ_E(r) = r²/χ_E with χ_E uniform (Eqs. 81–83), not the whole-plasma confinement time. Eqs. 140–142 make this explicit: P⊥(r̂) = (τ_R0/τ_E0)·ĵ_oh(r̂) with τ_E0 = a²/χ_E, so the r² cancels and P⊥ = μ₀χ_E/η(r_s). The whole-plasma time from W_e/P_e or a scaling law is τ̄_E = κ_e a²/χ_E (Eqs. 37–38), with κ_e = (3/2)∫₀¹ T̂_e r̂ dr̂ / [−dT̂_e(1)/dr̂].
With tau_E documented as the whole-plasma confinement time, this code's P⊥ differs from the paper's by r̂_s²/κ_e. For a T_e profile like (1 − r̂²), κ_e ≈ 0.19, so the 3/1 and 4/1 surfaces come out about 2–4× larger than Eq. 131 gives, and the error grows outward.
Two ways to make it match: take the whole-plasma τ̄_E and use P⊥ = τ_R(r_s)·κ_e a²/(r_s² τ̄_E), which needs κ_e from the T_e profile and the minor radius; or take a uniform χ_E (= κ_e a²/τ̄_E) as the input, which makes this mode the same as the χ-based P⊥ with one number for every surface. Either way, the docstring should say which confinement time is meant and cite Eqs. 81–83 alongside Eq. 131.
|
Thanks for the thorough review @d-burg I'd just like to reinforce that DIII-D data cannot be included in this open repo directly. The approach for the "DIIID-like" example should be to cite a paper if available and make a roughly matching functional form of the profile needed. Ideally, note the functional form somewhere in annotations / docs so it's clear its not a direct profile fit to data (eg "y = y0 (1 -x^2) where y0=3.0 roughly matches [Name Journal 2026]" or some such). |
Brings in the post-solve TearingProblem API, the TOML renames, Z_eff(ψ) from the kinetic file and the layer-overlap cap. The P_perp_model options now reach build_slayer_inputs through TearingProblem, and the layer-overlap scan takes the same chi_perp_e, chi_perp_i, tau_E and P_perp_model as the SLAYER stage, through one helper that also warns only about a missing χ the selected model uses. Review changes folded into the resolved hunks: - D_perp writes the Eq. 16 weights over one denominator, n T_s'/p', so a flat species temperature no longer gives 0·∞. - chi_perp_i has no default (NaN), and every P_perp model now rejects a non-finite or non-positive P_perp. - tau_E is the whole-plasma confinement time: a uniform χ_E = (3/16)a²/τ̄_E sets P_perp and P_tor at each surface (Fitzpatrick 2023, Eqs. 37-38, 81-83, 131), with a taken from the boundary on the same radial label as r_s. Before, P_perp = τ_R/τ̄_E was too large by r̂_s²/κ_e. A non-finite tau_E is caught at validation. - Docstrings: units no longer parse as Markdown links, Park (2022) is cited at Eq. 9, and Eq. 16's symbols and the orientation of its temperature ratio are defined. - An old deck's chi_perp key gets a hint that it is now chi_perp_e. The kinetic file is rebuilt from develop's copy, so #298's chi_e raise is kept. chi_e and chi_phi are replaced, and chi_i added, as analytic profiles in psi_N rather than profiles derived from a measured discharge; n, T and omega_E are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… and the tau_E conversion, with a D_perp harness case Adds a T_e ≠ T_i point that fixes the orientation of Eq. 16's temperature ratio, the flat-temperature c_β² floor, the missing and zero chi_perp_i errors, and the τ̄_E → χ_E conversion, both in slayer_parameters and through build_slayer_inputs (gradients from the profile splines, minor radius from the boundary). The new diiid_slayer_n1_d_perp case reruns the SLAYER deck with P_perp_model = D_perp, so the non-default models have a baseline. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…inetic file and the P_perp models States the three analytic forms with their sources: Hong et al. (2023) for the magnitude of χ_e and χ_i, Yoshida et al. (2012) for χ_φ tracking χ_i, and Callen et al. (2010) for the pedestal barrier the forms do not resolve. Replaces the stability docs' note that separating the electron and ion channels was deferred with the P_perp_model options, and adds chi_i to the kinetic schema. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…x label Every P_perp model is μ₀χ/η, so r_s cancels and the only radial label left in tau_E mode is the minor radius a in χ_E = (3/16)a²/τ̄_E. The outboard midplane chord, the default rs_method, is shortened by the Shafranov shift and ignores elongation; the flux label √(2ψ_t/B₀) is the area-equivalent radius of the boundary and reduces to the minor radius on circular surfaces. tau_E mode now uses it whatever rs_method is. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…erp models Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nd pin the truncation deck to chi_perp_e [SLAYER] P_perp_model now defaults to D_perp, the perpendicular particle diffusivity of Fitzpatrick (2022) Eq. 16, which is the coefficient the layer equations and the Eq. 100 width call for. On the DIII-D-like profiles it is 0.22-0.32 of chi_e at the outer rational surfaces, so SLAYER growth rates move and the layers are about 30% narrower. A run that selects D_perp or chi_perp_i without a chi_i profile or a chi_perp_i value now stops with a message naming the three ways to supply one. slayer_parameters keeps chi_perp_e as its own default, since it has no profile gradients. Under D_perp the layers on the DIII-D-like profiles no longer overlap inside psi = 1, so the truncation deck pins chi_perp_e to keep exercising the layer-overlap cap; it still caps psilim at 0.99498 with q = 6 the last surface. The D_perp harness case becomes diiid_slayer_n1_chi_perp_e, a baseline for the electron-channel model. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Release note
diiid_slayer_n1is 0.22–0.33 of the old electron-χ value, so γ moves by +31 % (2/1), +18 % (3/1) and +24 % (4/1) while ω moves by ≤ 0.4 %. The new analytic χ profiles of the DIII-D-like kinetic file alone move γ by ≤ 1.5 %. The layer-overlap cap ofdiiid_truncation_n1is unchanged (its widths move 2 %). (harness @ 4ce6bfe)[SLAYER], renamechi_perptochi_perp_e(also thechi_perpkeyword ofbuild_slayer_inputsandslayer_parameters). The new defaultP_perp_model = "D_perp"needs the ion diffusivity χ⊥,i: add achi_iprofile to the kinetic file or setchi_perp_i, or setP_perp_model = "chi_perp_e"to keep the previous P_⊥.tau_Eis the whole-plasma confinement time.SLAYER's perpendicular Prandtl number P_⊥, which enters the inner-layer Δ(Q) with P_φ, can now be built several ways through
[SLAYER] P_perp_model, and by default comes from the perpendicular particle diffusivity of Fitzpatrick (2022), Eq. 16. The critical Δ keeps the electron χ⊥,e in every mode, so the two are no longer forced to be the same diffusivity. The kinetic HDF5 schema gains an optionalchi_iprofile.P_perp_modelD_perp(default)chi_perp_echi_perp_iP_phic_betaD_perptau_EWhat changed
slayer_parameters, selected by[SLAYER] P_perp_modeland passed throughTearingProblemand the layer-overlap scan, so the scan and the tearing stage see one plasma.D_perpdefault. A run that needs χ⊥,i and has neither achi_iprofile norchi_perp_istops with a message naming both.slayer_parameterskeepschi_perp_eas its own default, since it has no profile gradients.tau_Etakes the whole-plasma τ̄_E, converted to a uniform χ_E with κ_e = 3/16 (the T_e ∝ 1 − r̂² value of Eq. 38) and the boundary minor radius from the flux label √(2ψ_t/B₀).TkMkr_D3Dlike_Hmode_kinetic.h5carries analytic χ profiles (below) in place of profiles derived from a measured discharge, and gainschi_i; n, T and ω_E are byte-identical to develop's. The forms and their sources are in the file'sprovenanceattribute and in the stability docs.P_perp_model = "chi_perp_e": underD_perpthe DIII-D-like layers are about 30 % narrower and do not overlap inside ψ = 1, so the pin keeps the layer-overlap cap exercised.diiid_slayer_n1_chi_perp_ekeeps a baseline for the previous model.stability.md,chi_iin the kinetic schema, the Fitzpatrick 2022 and 2023 papers indocs/resources, and the Park citation in the SLAYER file headers corrected to Phys. Plasmas 29, 072506 (2022).chi_perpis rejected with a hint that it is nowchi_perp_e.These are not fits to a discharge. Their magnitudes are of the same order as the TRANSP power-balance χ_e and χ_i of DIII-D H-modes in Hong et al., Phys. Plasmas 30, 072512 (2023), Fig. 5; χ_e keeps the factor-2 raise that makes the default deck exercise the overlap cut; χ_φ tracks χ_i (Prandtl number of order one, rising outward) as reported for DIII-D by Yoshida et al., Nucl. Fusion 52, 123005 (2012). They do not resolve the pedestal transport barrier, where power-balance χ falls to about 0.1–0.3 m²/s (Callen et al., Nucl. Fusion 50, 064004 (2010)).
Regression report
regress --refs 9fb32c9a6,4ce6bfea5 --forceon feynman, all 20 cases (develop against this branch with develop merged). Tests and the docs build pass at the head.diiid_slayer_n1diiid_slayer_n1_chi_perp_e(new)diiid_slayer_n1, the effect of the analytic χ alonediiid_truncation_n1Full regression report
diiid_slayer_n1_chi_perp_efails on develop, which does not knowP_perp_model, so the harness exits with one failed run;gal_resistive_peextracts nothing on either ref, as on develop. Every other case is unchanged.Notes for reviewers
D_perpdefault, the analytic χ and the docs are on top.tau_Ecarries a radial label, througha; it uses the flux label whateverrs_methodis, so the pending radial-label default change (InnerLayer.SLAYER - API - Choose one default radial label for the Fitzpatrick layer formalism #417) does not touch these models.chi_tordocstrings in the same files: whichever merges second needs a small conflict resolution.NO MERGE WITHOUT HUMAN REVIEW. This PR needs a third-party human reviewer's approval of the head that lands.
🤖 Generated with Claude Code